#!/usr/bin/env python
# encoding: utf-8
"""
@time: 2016/11/16 下午2:11
"""
# 三角函数的化简
from mathsolver.functions.base import *
from sympy import sin, cos, trigsimp, expand
from mathsolver.functions.sanjiao import sanjiao_utils as su
from mathsolver.functions.budengshi import common_opers as co
import copy


def my_trig_simp(trig_f):
    sim_trig_f = trig_f
    try:
        sim_trig_f, _ = su.trig_simp(trig_f)
    except Exception:
        pass
    return sim_trig_f


# 二倍角公式[降幂]
def trig_simp001(trig_f):
    trig_f = expand(trig_f)
    # 首先判断是否含有二次项 。如果含有则进行后续操作，否则跳出去。
    quadr_trigs = co.find_reg_expr(r'sin\(.*?\)\*\*2', str(trig_f))
    quadr_trigs = quadr_trigs if quadr_trigs else co.find_reg_expr(r'cos\(.*\)\*\*2', str(trig_f))
    if not quadr_trigs:
        return trig_f
    quadr_trig = sympify(quadr_trigs[0])
    trig_arg = quadr_trig.args[0].args[0]
    sim_f = trig_f
    if str(quadr_trig).find('sin') >= 0:
        sim_f = trig_f.subs(quadr_trig, (1 - cos(expand(2 * trig_arg))) / 2)
    elif str(quadr_trig).find('cos') >= 0:
        sim_f = trig_f.subs(quadr_trig, (1 + cos(expand(2 * trig_arg))) / 2)
    sim_f = simplify(sim_f)
    return sim_f


# 积化和差公式
def trig_simp002(trig_f):
    trig_f = sympify(trig_f)
    patterns = [r'sin\(.*?\)\*cos\(.*?\)', r'cos\(.*?\)\*sin\(.*?\)', r'cos\(.*?\)\*cos\(.*?\)',
                r'sin\(.*?\)\*sin\(.*?\)']
    exprs = list(filter(lambda _: _, map(lambda pattern: co.find_reg_expr(pattern, str(trig_f)), patterns)))
    if exprs:
        mul_trig_f = sympify(exprs[0][0])
        trig_1, trig_2 = mul_trig_f.args
        type1, type2 = type(trig_1), type(trig_2)
        trig_1_arg = trig_1.args[0]
        trig_2_arg = trig_2.args[0]
        sub_trig = mul_trig_f
        coef = sympify('1/2')
        if type1 == sin and type2 == cos:
            sub_trig = coef * (sin(trig_1_arg + trig_2_arg) + sin(trig_1_arg - trig_2_arg))
        elif type1 == cos and type2 == sin:
            sub_trig = coef * (sin(trig_1_arg + trig_2_arg) - sin(trig_1_arg - trig_2_arg))
        elif type1 == cos and type2 == cos:
            sub_trig = coef * (cos(trig_1_arg + trig_2_arg) + cos(trig_1_arg - trig_2_arg))
        elif type1 == sin and type2 == sin:
            sub_trig = coef * (cos(trig_1_arg + trig_2_arg) - cos(trig_1_arg - trig_2_arg))
        return simplify(trig_f.subs(mul_trig_f, sub_trig))
    return trig_f


def trig_simp003(trig_f):
    return trig_f


trig_sim_fs = [trigsimp, my_trig_simp, trig_simp001, trig_simp002, trig_simp003]


# 三角函数终极化简
def trig_simplify(expr):
    """
    三角函数终极化简
    :param expr: 三角函数表达式
    :return:
    """

    def _is_simped(cur_expr):
        """
        是否已经处于化简状态.形如A*sin(g(x)) + h 或者 A*cos(g(x)) + h
        :param cur_expr:
        :return:
        """
        cur_expr = sympify(cur_expr)
        if cur_expr.is_real:
            return cur_expr
        coefs_d = co.coefficients_dict(cur_expr)
        if len(coefs_d.items()) > 2:
            return False
        trig_mon, const = co.split_mons_const(cur_expr)
        coef = su.trig_coeff(trig_mon)
        if str(coef).find('sin') >= 0 or str(coef).find('cos') >= 0 or str(coef).find('tan') >= 0 or str(coef).find(
                'cot') >= 0:
            return False
        trig = trig_mon / coef
        if str(type(trig)) in ['sin', 'cos', 'tan', 'cot']:
            return True
        else:
            return False

    def _expr_converts(cur_expr):
        """
        表达式转换
        :param cur_expr:
        :return:
        """
        exprs = []
        for sim_f in trig_sim_fs:
            temp_expr = sim_f(cur_expr)
            if _is_simped(temp_expr):
                exprs.append(temp_expr)
                break
            else:
                exprs.append(temp_expr)
        return exprs

    def _expr_list_eqed(expr_list1, expr_list2):
        """
        两个表达式列表是否相等
        :param expr_list1:
        :param expr_list2:
        :return:
        """
        if len(expr_list1) != len(expr_list2):
            return False
        expr_list1 = map(lambda temp_expr: sympify(str(temp_expr)), expr_list1)
        expr_list2 = map(lambda temp_expr: sympify(str(temp_expr)), expr_list2)
        for cur_expr in expr_list1:
            if cur_expr not in expr_list2:
                return False
        return True

    def _haved_expr(expr_list, cur_expr):
        """
        表达式列表中是否含有当前表达式
        :param expr_list: 表达式列表
        :param cur_expr: 当前表达式
        :return:
        """
        expr_list = map(lambda temp_expr: sympify(str(temp_expr)), expr_list)
        cur_expr = sympify(str(cur_expr))
        for tmp_expr in expr_list:
            if tmp_expr == cur_expr:
                return True
        return False

    expr = simplify(expr)
    if su.trig_is_simped(expr):  # old :_is_simped(expr):
        return expr
    # 先用sumpy自带的化简进行化简 如果可以 就不用再进行化简了
    _expr = simplify(expr)
    if su.trig_is_simped(_expr):
        return _expr
    prev_exprs = [expr, ]
    next_exprs = [expr, ]
    firsted = True
    simped = False
    last_expr = expr
    while (not simped) and (firsted or (not _expr_list_eqed(prev_exprs, next_exprs))):
        firsted = False
        prev_exprs = copy.copy(next_exprs)
        for prev_expr in prev_exprs:
            if simped:
                break
            deduce_exprs = _expr_converts(prev_expr)
            for deduce_expr in deduce_exprs:
                if _is_simped(deduce_expr):
                    last_expr = deduce_expr
                    simped = True
                    break
                elif not _haved_expr(next_exprs, deduce_expr):
                    next_exprs.append(deduce_expr)
    return last_expr


class SanJiaoHuaJian(BaseFunction):
    def solver(self, *args):
        trig_f = args[0]
        if isinstance(trig_f, BaseSinPoly):
            trig_f = trig_f.sympify()
        elif isinstance(trig_f, BaseSinFunc):
            trig_f = sympify(trig_f.value['expression'])
        simp_trig_f = trigsimp(trig_f)
        if su.trig_simped(simp_trig_f):  # 如果sympy自带的已经足够，那么就不需要了
            steps = [new_latex(simp_trig_f), ]
        else:
            try:
                for trig_sim_f in trig_sim_fs:
                    simp_trig_f, steps = trig_sim_f(trig_f)
                    if su.trig_simped(simp_trig_f):
                        break
            except Exception:
                pass
        for s in steps:
            self.steps.append(['= ', s])
        self.steps.append(['= ' + new_latex(simp_trig_f), ''])
        self.output.append(BasePoly(simp_trig_f))
        return self


class SanJiaoHuaJianTest(BaseFunction):
    def solver(self, *args):
        # self.label.add('三角化简')
        self.steps.append(['测试三角函数化简', ''])
        self.output.append(BaseNumber(1))
        return self


if __name__ == '__main__':
    pass
